package core;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class Perplexity {
	
	private MLE mle;
	private Laplace laplace;
	private Smoothing interpol;
	private String sentence;
	private int lengthNgram;
	private Tools tool;
	private Hashtable<String, BigDecimal> htProbCartoons;
	private Hashtable<String, Double> htProbs;
	private Hashtable<String, Double> htPerplexity;
	private double totalPerplexity;
	
	public Perplexity(String sentence,int lengthNgram,String mode){
		tool = new Tools();
		this.sentence=sentence;	
		
		this.lengthNgram=lengthNgram;
		
		htProbCartoons = new Hashtable<>();
		
		htPerplexity = new Hashtable<>();
		
		htProbs = new Hashtable<>();
		
		chooseMode(mode);
	}
	
	private void chooseMode(String mode){
		switch (mode) {
		case "None":
			if(tool.checkString(sentence))
				mle = new MLE(sentence);
				else
					mle=new MLE();
			break;
		case "Laplace":
			laplace = new Laplace(sentence, lengthNgram);
			break;
		case "Interpol":
			interpol=new Smoothing(lengthNgram, sentence);
			break;
		}
	}
	
	public double calculatePerplexity(String pathCorpus,String pathCartoons) throws IOException{
		if(lengthNgram==1)
			mle.processUnigram(pathCorpus, pathCartoons);
		else
		mle.countNGram(pathCorpus, pathCartoons);
		
		mle.calculateMLE();
		
		htProbCartoons=mle.getProbCartoons();
		double exp=((double) 1/(double)lengthNgram);
		
		Enumeration<String> keys= htProbCartoons.keys();
		while(keys.hasMoreElements()){
			String key =keys.nextElement();
			BigDecimal value =htProbCartoons.get(key);
			double prob=value.doubleValue();
			//TODO DEBUG
			//System.out.println(prob);
			
			double base = Math.pow((double)1/prob, (double)lengthNgram);
			System.out.println("Base: "+base);
			double perplexity = Math.pow(base,(double) -exp);
			htPerplexity.put(key, perplexity);
		}
		
		Enumeration<String> claves = htPerplexity.keys();
		 totalPerplexity =0;
		while(claves.hasMoreElements()){
			String key = claves.nextElement();
			double value = htPerplexity.get(key);
			//TODO DEBUG
			System.out.println("Perplejidad--> Clave: "+key+" Valor: "+value);
			totalPerplexity+=value;
		}
		//TODO DEBUG
		System.out.println("Total Perplejidad: "+totalPerplexity);
		return totalPerplexity;
	}
	
	public double calculatePerplexityLaplace(String pathCorpus,String pathCartoons) throws IOException{
		
		
			laplace.smoothingLaplace(pathCorpus, pathCartoons);
			
			htProbs= laplace.getHtLaplace();
			
			double exp=((double) 1/(double)lengthNgram);
			
			Enumeration<String> keys= htProbs.keys();
			while(keys.hasMoreElements()){
				String key =keys.nextElement();
				double prob=htProbs.get(key);
				//TODO DEBUG
				//System.out.println(prob);
				
				double base = Math.pow((double)1/prob, (double)lengthNgram);
				//System.out.println("Base: "+base);
				double perplexity = Math.pow(base,(double) -exp);
				htPerplexity.put(key, perplexity);
			}
			
			Enumeration<String> claves = htPerplexity.keys();
			double total =0;
			while(claves.hasMoreElements()){
				String key = claves.nextElement();
				double value = htPerplexity.get(key);
				//TODO DEBUG
				System.out.println("Perplejidad--> Clave: "+key+" Valor: "+value);
				total+=value;
			}
			//TODO DEBUG
			System.out.println("Total Perplejidad: "+total);
		
		return total;
	}
	
	public void writeResults(String path){
		String ext = ".txt";
		path+=ext;
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(path));
			ArrayList probs = new ArrayList(htPerplexity.entrySet());
			Collections.sort(probs,new ComparatorHash());
			Iterator it = probs.iterator();
			String key = " ";
			
			bw.write("Serie");
			bw.write("\t");
			bw.write("Perplejidad");
			
			while(it.hasNext()){
				Map.Entry<String, Double> e = (Entry<String, Double>) it.next();
				key = e.getKey();
				Double value = e.getValue();
				
				bw.newLine();
				bw.write(key);
				bw.write("\t");
				bw.write(String.valueOf(value));
			}
			//Almacena el total
			bw.newLine();
			bw.write("Total:");
			bw.write("\t");
			bw.write(String.valueOf(totalPerplexity));
			
			bw.close();
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
	}
	
	public boolean checkPerplexity(){
		if(htPerplexity.isEmpty())
			return false;
		else
			return true;
	}
	
	public double calculatePerplexityInterpol(String pathCorpus,String pathCartoons) throws IOException{
		
		interpol.interpolationSmoothing(pathCorpus, pathCartoons, sentence);
		interpol.calculateProbInterpolation();
		
		htProbCartoons=interpol.getHtProbabilities();
		
double exp=((double) 1/(double)lengthNgram);
		
		Enumeration<String> keys= htProbCartoons.keys();
		while(keys.hasMoreElements()){
			String key =keys.nextElement();
			BigDecimal value =htProbCartoons.get(key);
			double prob=value.doubleValue();
			//TODO DEBUG
			//System.out.println(prob);
			
			double base = Math.pow((double)1/prob, (double)lengthNgram);
			System.out.println("Base: "+base);
			double perplexity = Math.pow(base,(double) -exp);
			htPerplexity.put(key, perplexity);
		}
		
		Enumeration<String> claves = htPerplexity.keys();
		double total =0;
		while(claves.hasMoreElements()){
			String key = claves.nextElement();
			double value = htPerplexity.get(key);
			//TODO DEBUG
			System.out.println("Perplejidad--> Clave: "+key+" Valor: "+value);
			total+=value;
		}
		//TODO DEBUG
		System.out.println("Total Perplejidad: "+total);
		return total;				
	}

}
